﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.ServiceModel;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SecurityClient;

namespace SecurityModule.Workflows
{
    class WFPostAppAnalysisReport : IWorkflow
    {
        private const string AnalysisPrefix = "/App/Analysis/Report";

        public void PreProcess(HttpContext context)
        {
            if (context.Request.FilePath.StartsWith(AnalysisPrefix, true, CultureInfo.InvariantCulture) &&
                context.Request.RequestType == "POST")
            {
                var callback = new Func<string, string>(formFields =>
                {
                    var fields = HttpUtility.ParseQueryString(formFields);
                    try
                    {
                        var security = new SecurityServiceProxy();
                        var result = security.GetPublicKey();
                        if (result.Success)
                        {
                            if (fields.AllKeys.Contains("PublicKey"))
                                fields["PublicKey"] = result.PublicKey;
                            else
                                fields.Add("PublicKey", result.PublicKey);
                            var defaultValResult = security.Encrypt(0.0M);
                            if (defaultValResult.Success)
                            {
                                if (fields.AllKeys.Contains("DefaultValue"))
                                    fields["DefaultValue"] = defaultValResult.EncryptedValue;
                                else
                                    fields.Add("DefaultValue", defaultValResult.EncryptedValue);
                            }
                            else
                            {
                                if (fields.AllKeys.Contains("DefaultValue"))
                                    fields["DefaultValue"] = "";
                                else
                                    fields.Add("DefaultValue", "");
                                if (fields.AllKeys.Contains("EXTERRMSG"))
                                {
                                    fields["EXTERRMSG"] = defaultValResult.ErrorMessage;
                                }
                                else
                                {
                                    fields.Add("EXTERRMSG", defaultValResult.ErrorMessage);
                                }
                            }
                        }
                        else
                        {
                            if (fields.AllKeys.Contains("PublicKey"))
                                fields["PublicKey"] = "";
                            else
                                fields.Add("PublicKey", "");
                            if (fields.AllKeys.Contains("EXTERRMSG"))
                            {
                                fields["EXTERRMSG"] = result.ErrorMessage;
                            }
                            else
                            {
                                fields.Add("EXTERRMSG", result.ErrorMessage);
                            }
                        }
                    }
                    catch (Exception exception)
                    {
                        if (exception is PipeException || exception is EndpointNotFoundException)
                        {
                            //If the security service is offline or broken
                            if (fields.AllKeys.Contains("EXTERRMSG"))
                            {
                                fields["EXTERRMSG"] = SimpleWorkflow.SecurityServiceDownMsg;
                            }
                            else
                            {
                                fields.Add("EXTERRMSG", SimpleWorkflow.SecurityServiceDownMsg);
                            }
                        }
                        else
                        {
                            if (fields.AllKeys.Contains("EXTERRMSG"))
                            {
                                fields["EXTERRMSG"] = exception.Message;
                            }
                            else
                            {
                                fields.Add("EXTERRMSG", exception.Message);
                            }
                        }
                    }
                    return fields.ToString();
                });
                context.Request.Filter = new RequestFilter(context.Request.Filter, context.Request.ContentEncoding, callback);
                context.Response.Filter = new ReplaceFilter(
                    context.Response.Filter,
                    context.Response.ContentEncoding,
                    content =>
                    {
                        var format = "{0:F2}";
                        if (context.Request.Form["DataPresentation"] == "Data Table")
                            format = "{0:C2}";
                        var sb = new StringBuilder(content);
                        var decryptRegex = new Regex("{{([0-9A-F]+)}}", RegexOptions.IgnoreCase);
                        var decryptRegexMatch = decryptRegex.Match(content);
                        var decryptRegexReplacements = new List<string>();
                        while (decryptRegexMatch.Success)
                        {
                            var withoutBraces = decryptRegexMatch.Groups[1].Captures[0];
                            if (!decryptRegexReplacements.Contains(withoutBraces.Value))
                                decryptRegexReplacements.Add(withoutBraces.Value);
                            decryptRegexMatch = decryptRegexMatch.NextMatch();
                        }
                        var encrypted = decryptRegexReplacements.ToArray();
                        try
                        {
                            var security = new SecurityServiceProxy();
                            var decryptionResult = ChunkArrayOperation.BulkDecryptInChuncks(security, encrypted, 500);
                            if (decryptionResult.Success)
                            {
                                for (var i = 0; i < encrypted.Length; i++)
                                {
                                    sb.Replace(string.Format("{{{{{0}}}}}", encrypted[i]), string.Format(format, decryptionResult.Values[i]));
                                }
                            }
                            else
                            {
                                foreach (var val in encrypted)
                                {
                                    sb.Replace(string.Format("{{{{{0}}}}}", val), string.Format(format, 0));
                                }
                            }
                        }
                        catch
                        {
                            foreach (var val in encrypted)
                            {
                                sb.Replace(string.Format("{{{{{0}}}}}", val), string.Format(format, 0));
                            }
                        }
                        var res = sb.ToString();
                        sb = new StringBuilder(res);
                        var summarizeRegex = new Regex("SUMMARIZE4PIE<<(.+)>>", RegexOptions.IgnoreCase);
                        var summarizeRegexMatch = summarizeRegex.Match(res);
                        var summarizeRegexReplacements = new List<string>();
                        while (summarizeRegexMatch.Success)
                        {
                            var dataTable = summarizeRegexMatch.Groups[1].Captures[0];
                            if (!summarizeRegexReplacements.Contains(dataTable.Value))
                                summarizeRegexReplacements.Add(dataTable.Value);
                            summarizeRegexMatch = summarizeRegexMatch.NextMatch();
                        }
                        var tables = summarizeRegexReplacements.ToArray();
                        foreach (var table in tables)
                        {
                            var obj = JsonConvert.DeserializeObject<JArray>(table);
                            var headerArr = obj[0].ToArray();
                            var header = string.Format("[{0},{1}]", headerArr[0].Value<string>(),
                                                       headerArr[1].Value<string>());
                            var data = obj.Skip(1).Select(token =>
                                {
                                    var items = token.ToArray();
                                    return new { Business = items[0].ToString(), Value = items[1].Value<float>() };
                                });
                            data = data.OrderByDescending(item => item.Value);
                            var theRest = data.Skip(9).Select(item => item.Value).Sum();
                            var result = header + "," + data.Take(9).Select(
                                item => string.Format("[{0},{1}]", item.Business, item.Value)).
                                              Concat(new[] { string.Format("['Other',{0}]", theRest) }).
                                              Aggregate((a, b) => a + "," + b);
                            sb.Replace(string.Format("SUMMARIZE4PIE<<{0}>>", table), result);
                        }
                        res = sb.ToString();
                        return res;
                    });
            }
        }

        public void PostProcess(HttpContext context)
        {

        }
    }
}